package cn.yiyuan.auth.service.imp;

import cn.yiyuan.auth.domain.Permission;
import cn.yiyuan.base.annotate.Authority;
import cn.yiyuan.base.enums.RequestTypeEnum;
import cn.yiyuan.base.until.ClassUtils;
import cn.yiyuan.auth.service.IPermissionScanService;
import cn.yiyuan.auth.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * @user m
 * @project system
 * @date 2023-10-28
 * @package cn.yiyuan.org.service.impl
 */

@Transactional
@Service
public class PermissionScanServiceImpl implements IPermissionScanService {

    @Value("${yiyuan.permission.scan-package}")
    private String url;

    @Autowired
    private PermissionService permissionService;
    /*
        权限和 父权限. 如果接口上有 权限 那个这类 一定有权限
    */
    @Override
    public void scan() {
        // 清空权限表
        permissionService.deleteAll();
        // 扫描的资源 ?
        // 想获取注解 > 类 > 包路径 = 包的全限定名 + 项目的路径
        List<Class> allClassName = ClassUtils.getAllClassName(url);
        // 遍历集合
        for (Class clazz: allClassName ) {
            //  1. 判断该controller是否有权限注解
            Authority annotation = (Authority)clazz.getAnnotation(Authority.class);
            RequestMapping requestMapping = (RequestMapping)clazz.getAnnotation(RequestMapping.class);
            if (Objects.isNull(annotation)){
                continue;
            }
            // 封装权限父对象
            Permission parent = new Permission();
            parent.setDescs(annotation.descs());
            parent.setName(annotation.name());
            parent.setSn(clazz.getSimpleName()); // controller:方法名
            String parentUrl = requestMapping.value()[0];
            // String parentUrl = Arrays.toString(value);
            parent.setUrl(parentUrl);// controller的路径 + 方法的上的路径
            // 父权限要先入库
            permissionService.insert(parent);
            //  如果有权限 那么 应该拿到所有的方法
            Method[] methods = clazz.getMethods();
            // 遍历判断每一个方法是否要权限
            for (Method m: methods) {
                Authority annotation1 = m.getAnnotation(Authority.class);
                if (Objects.isNull(annotation1)){
                    continue;
                }
                // 3. 如果方法需要权限  获取注解 封装权限对象
                Permission permission = new Permission();
                permission.setDescs(annotation1.descs());
                permission.setName(annotation1.name());
                permission.setParent(parent);
                String  sn = clazz.getSimpleName()+":"+ m.getName();
                permission.setSn(sn); // controller:方法名

                // 获取方法上的 url
                String methodUrl = getMethodUrl(m);
                // 首先要判断 方法上的 注解类型
//                GetMapping annotation2 = m.getAnnotation(GetMapping.class);
//                if (Objects.nonNull(annotation2)){
//                    String[] value = annotation2.value();
//                    System.out.println(Arrays.toString(value));
//                    // 如果,某一个Mapping中 有url 那么 value数组 取 0
//                    methodUrl = value.length == 0 ? "":value[0];
//                }

                permission.setUrl(parentUrl +methodUrl);// controller的路径 + 方法的上的路径
                permissionService.insert(permission);

            }

        };


    }

    public String getMethodUrl(Method method){
        String methodUrl = "";
        // 取枚举中定义的所有的请求类型
        RequestTypeEnum[] requestTypeEnums = RequestTypeEnum.values();
        for (RequestTypeEnum typeEnum : requestTypeEnums) {
            // 根据枚举中的不同的请求类型的class获取该类型对应的注解对象
            Annotation annotation = method.getAnnotation(typeEnum.getRequestType());
            // 如果该请求类型注解不存在就跳过
            if(Objects.isNull(annotation)){
                continue;
            }
            try {
                // 如果该请求类型注解存在,就获取它里面的value方法
                Class<? extends Annotation> aClass = annotation.annotationType();
                Method annotationMethod = aClass.getMethod("value");
                // 通过invoke调用该对象的value方法,获取结果
                // 反射执行 方法 方法名.invoke(对象)
                String[] value = (String[]) annotationMethod.invoke(annotation);
                // 如果value不为空且长度大于0,就赋值给methodUrl,并跳出循环
                if(value != null && value.length > 0){
                    methodUrl = value[0];
                    break;
                }
            }catch (Exception e) {
                e.printStackTrace();
                continue;
            }
        }
        return methodUrl;

    }
}
